package com.xayy.mgt.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.kawins.base.result.CheckResult;
import cn.kawins.base.utils.BeanUtil;
import cn.kawins.base.utils.StringUtil;
import com.xayy.core.antlr4.model.ErrorResult;
import com.xayy.core.antlr4.utils.FunUtil;
import com.xayy.core.antlr4.utils.Golabl;
import com.xayy.core.antlr4.visitor.HealthEvaluateVisitor;
import com.xayy.core.constant.BayesArgs;
import com.xayy.core.constant.ConfigCalPath;
import com.xayy.mgt.model.EquipTreeInfo;
import com.xayy.mgt.model.HealthDeep;
import com.xayy.mgt.model.NodeTreeInfo;
import com.xayy.mgt.model.vo.DataInfoVo;
import com.xayy.mgt.model.vo.EvaluationVo;
import com.xayy.mgt.model.xinwangmodel.HealthEntity;
import com.xayy.mgt.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 对外接口
 * @author plq
 */
@Service
@Slf4j
public class OutInterfaceServiceImpl implements OutInterfaceService {

    @Autowired
    private HealthSituationService healthSituationService;

    @Autowired
    private NodeInfoService nodeInfoService;

    @Autowired
    private HealthDeepService healthDeepService;
    
    @Autowired
    private BayesService bayesService;

    @Autowired
    private BayesArgs bayesArgs;

    @Autowired
    private EquipTreeService equipTreeService;

    @Autowired
    private GenerateAssessDataService generateAssessDataService;

    @Autowired
    private HistoryFaultService historyFaultService;


    @Autowired
    private ConfigCalPath configCalPath;


    /**
     * 卫星健康流程日志
     */
    public static List<String> HealthFlowLogs = new ArrayList<>();
    public static boolean healthAddLogs;

    /**
     * 贝叶斯流程日志
     */
    public static List<String> bayesFlowLogs = new ArrayList<>();
    public static boolean bayesAddLogs;

    /**
     * 星座评估流程日志
     */
    public static List<String> xzFlowLogs = new ArrayList<>();
    public static boolean xzFlowAddLogs;

    /**
     * 日志添加
     */
    public static void addLogs(String log){
        if(healthAddLogs){
            HealthFlowLogs.add(DateUtil.format(new Date() ,"yyyy-MM-dd HH:mm:ss.SSS")+" "+log);
        }
    }

    public static void addBayesLogs(String log){
        if(bayesAddLogs){
            bayesFlowLogs.add(DateUtil.format(new Date() ,"yyyy-MM-dd HH:mm:ss.SSS")+" "+log);
        }
    }

    public static void addXZLogs(String log){
        if(xzFlowAddLogs){
            xzFlowLogs.add(DateUtil.format(new Date() ,"yyyy-MM-dd HH:mm:ss.SSS")+" "+log);
        }
    }

    @Override
    public CheckResult<Object> generateAssessData(String satelliteCode,String componentCode,Date time) {
        /*查询卫星节点信息*/
        NodeTreeInfo sateMsg = nodeInfoService.selectOne(NodeTreeInfo.builder().nodeCode(satelliteCode).build());
        if(sateMsg == null){
            return CheckResult.fail("暂无该卫星信息");
        }
        NodeTreeInfo nodeTreeInfo = sateMsg;
        if(StringUtil.isNotBlank(componentCode)){
            nodeTreeInfo = nodeInfoService.selectOne(NodeTreeInfo.builder().nodeCode(componentCode).satelliteId(sateMsg.getSatelliteId()).build());
            if(nodeTreeInfo == null){
                return CheckResult.fail("暂无该器部件信息");
            }
        }
        /*查询卫星健康度*/
        return healthSituationService.getHealthSituationInfo(nodeTreeInfo.getId(),time);
    }

    @Override
    public CheckResult<Object> getSatelliteHealthFlow(String satelliteCode, Date time,String componentCode) {
        /*清除日志*/
        HealthFlowLogs.clear();
        healthAddLogs = true;
        addLogs("计算开始");
        /*查询卫星节点信息*/
        NodeTreeInfo sateMsg = nodeInfoService.selectOne(NodeTreeInfo.builder().nodeCode(satelliteCode).build());
        if(sateMsg == null){
            addLogs("暂无该卫星信息");
            healthAddLogs = false;
            return CheckResult.fail("暂无该卫星信息");
        }
        NodeTreeInfo nodeTreeInfo = sateMsg;
        if(StringUtil.isNotBlank(componentCode)){
            /*查询器部件*/
            nodeTreeInfo = nodeInfoService.selectOne(NodeTreeInfo.builder().nodeCode(componentCode).satelliteId(sateMsg.getSatelliteId()).build());
            if(nodeTreeInfo == null){
                addLogs("暂无该器部件信息");
                healthAddLogs = false;
                return CheckResult.fail("暂无该器部件信息");
            }
        }
        addLogs("获取卫星信息:"+sateMsg);
        addLogs("获取器部件信息:"+nodeTreeInfo);
        // 计算前清理缓存
        Golabl.clear(nodeTreeInfo.getSatelliteId());
        HealthDeep healthDeep = healthDeepService.selectOne(HealthDeep.builder().nodeId(nodeTreeInfo.getId()).build());
        if (BeanUtil.isEmpty(healthDeep)) {
            addLogs("评估节点没有构建评估体系，请去评估体系构建模块配置该节点评估信息");
            healthAddLogs = false;
            return CheckResult.fail("评估节点没有构建评估体系，请去评估体系构建模块配置该节点评估信息");
        }
        String customParam = healthDeep.getCustomParam();
        if (StrUtil.isBlank(customParam)) {
            addLogs("评估节点没有构建评估体系，请去评估体系构建模块配置该节点评估信息");
            healthAddLogs = false;
            return CheckResult.fail("评估节点没有构建评估体系，请去评估体系构建模块配置该节点评估信息");
        }
        // 计算正常情况下的健康度指标
        ErrorResult execute = FunUtil.execute(customParam, new HealthEvaluateVisitor(nodeTreeInfo.getSatelliteId(),
                nodeTreeInfo.getId(), time, false, false));
        if (execute.isSuccess()) {
            Double result = execute.getResult();
            // 计算有故障时候的健康度，卫星在轨时间到评估时刻做整个评估时间段，故障时长为该故障下的健康度所在比重，结合起来
            EvaluationVo evaluationVo = new  EvaluationVo();
            evaluationVo.setSatelliteId(nodeTreeInfo.getSatelliteId());
            evaluationVo.setNodeId(nodeTreeInfo.getId());
            evaluationVo.setEvaluationTime(time);
            CheckResult<Map<String, Double>> mapCheckResult = healthSituationService.errorEvaluation(customParam, evaluationVo);
            if (mapCheckResult.isSuccess()) {
                Double weight = mapCheckResult.getData().get("weight");
                Double score = mapCheckResult.getData().get("score");
                result = weight * result + score;
            }
            // 将数据存库
            healthSituationService.insertInfo(evaluationVo.getNodeId(), evaluationVo.getEvaluationTime(), result, healthDeep);
            addLogs("计算结束");
            healthAddLogs = false;
            return generateAssessData(satelliteCode,componentCode,time);
        }
        int code = execute.getCode();
        List<String> gramErrList = execute.getGramErrList();
        addLogs(gramErrList.toString());
        addLogs("计算结束");
        healthAddLogs = false;
        return CheckResult.fail(code, gramErrList.toString());
    }


    @Override
    public CheckResult<Object> getBayesAssessFlow(String componentCode, int errorSampling, int sampling, Date time) {
        bayesFlowLogs.clear();
        bayesAddLogs = true;
        addBayesLogs("计算开始");
        /*查询卫星信息*/
        /*查询卫星节点信息*/
        NodeTreeInfo sateMsg = nodeInfoService.selectOne(NodeTreeInfo.builder().id(bayesArgs.getNodeId()).build());
        if(sateMsg == null){
            addBayesLogs("暂无该卫星信息");
            bayesAddLogs = false;
            return CheckResult.fail("暂无该卫星信息");
        }
        NodeTreeInfo nodeTreeInfo = sateMsg;
        if(StringUtil.isNotBlank(componentCode)){
            /*查询器部件*/
            nodeTreeInfo = nodeInfoService.selectOne(NodeTreeInfo.builder().nodeCode(componentCode).satelliteId(sateMsg.getSatelliteId()).build());
            if(nodeTreeInfo == null){
                addBayesLogs("暂无该器部件信息");
                bayesAddLogs = false;
                return CheckResult.fail("暂无该器部件信息");
            }
        }
        /*历史故障同步*/
        OutInterfaceServiceImpl.addBayesLogs("历史故障同步："+configCalPath.getTelAndFaultUrl()+ "/health-xw-back-moni/v1.0/imitate/getHistoryFault?satelliteCode="+sateMsg.getNodeCode());
        try {
            historyFaultService.dataSynchronous(sateMsg.getSatelliteId());
        } catch (Exception e) {
            log.info("贝叶斯评估流程，历史同步调用模拟接口失败："+e.getMessage());
        }
        /*构建评估参数*/
        DataInfoVo dataInfoVo = DataInfoVo.builder()
                .nodeId(nodeTreeInfo.getId())
                .satelliteId(sateMsg.getSatelliteId())
                .systemId(nodeTreeInfo.getSystemId())
                .errorSampling(errorSampling)
                .sampling(sampling)
                .healthTime(time)
                .build();
        CheckResult<Object> objectCheckResult = bayesService.computeHealth(dataInfoVo);
        addBayesLogs("计算结束");
        bayesAddLogs = false;
        return objectCheckResult;
    }

    @Override
    public CheckResult<Object> getConstellationFlow(int algorithmType, String constellationName, Date time) {
        xzFlowLogs.clear();
        xzFlowAddLogs = true;
        addXZLogs("开始评估");
        /*查询星座id*/
        EquipTreeInfo equipTreeInfo = equipTreeService.selectOne(EquipTreeInfo.builder().nodeName(constellationName).build());
        if(equipTreeInfo == null){
            return CheckResult.fail("暂无该星座节点");
        }
        addXZLogs("获取节点数据："+equipTreeInfo);
        HealthEntity healthEntity = HealthEntity.builder()
                .nodeId(equipTreeInfo.getId())
                .time(time)
                .algorithmType(algorithmType)
                .build();
        CheckResult<Object> objectCheckResult = generateAssessDataService.healthAssess(healthEntity);
        addXZLogs("评估中，结果请查看评估历史");
        xzFlowAddLogs = false;
        return objectCheckResult;
    }
}
